import * as Cesium from '@cesiumjs';
import {G3vObj} from "@g3xbase"
import * as g3xUtils from "@g3x/utils";
import * as g3vUtils from "@g3v/utils";
import {
  autorun,
  reaction,
  intercept,
  extendObservable,
  computed
} from 'mobx';

import {
  G3xPolyline
} from '@g3vObjects';
import initSchema from "./schema";
import g3xExtends from "./extends";
import G3xWaterManager from "./WaterManager";

/* 320 */

function applyMaterial(primitive, water) {
  var uniforms = primitive.appearance.material.uniforms;
  Cesium.Color.apply(uniforms.baseWaterColor, water.baseWaterColor);
  Cesium.Color.apply(uniforms.blendColor, water.blendColor);
  uniforms.frequency = water.frequency;
  uniforms.animationSpeed = water.animationSpeed;
  uniforms.amplitude = water.amplitude;
  uniforms.specularIntensity = water.specularIntensity;
  uniforms.fadeFactor = water.fadeFactor;
  uniforms.sizeAndVelocity.z = water.velocity[0];
  uniforms.sizeAndVelocity.w = water.velocity[1];
}

function initWaterManager(scene) {
  !scene.g3xWaterManager && (scene.g3xWaterManager = new G3xWaterManager(scene))
}

/**
 * 水面
 * @memberof Obj
 * @class
 * @extends G3vObj
 **/
class G3xWater extends G3vObj {

  constructor(g3vViewer, options) {

    super(g3vViewer.viewer, options);
    
    const {viewer} = g3vViewer;
    var _this = this;
    const scene = viewer.scene;
    initWaterManager(scene);

    g3xUtils.g3x_defineReadonly(this, "g3xWaterManager", scene.g3xWaterManager)

    this.init()
  }

  init() {
    var _this = this;
    const {
      viewer,
      disposers,
      g3xWaterManager,
    } = this;

    disposers.push(g3xUtils.bind(_this, 'enabled', _this, 'show'));

    _this._primitive = undefined;
    disposers.push(function() {
      return _this._primitive && g3xWaterManager.destroyWaterPolygonPrimitive(_this._primitive);
    });
    _this._groundPrimitive = undefined;
    disposers.push(function() {
      return _this._groundPrimitive && g3xWaterManager.destroyWaterPolygonPrimitive(_this._groundPrimitive);
    });

    _this._boundingSphere = new Cesium.BoundingSphere();

    {
      function updatePolygonPrimitive() {
        if (_this._primitive) {
          _this._primitive.show = _this.show;
          applyMaterial(_this._primitive, _this);
        }

        if (_this._groundPrimitive) {
          _this._groundPrimitive.show = _this.show;
          applyMaterial(_this._groundPrimitive, _this);
        }
      };

      disposers.push(reaction(() => {
        return {
          // color: [...this.color],
          show: _this.show,
          baseWaterColor: [..._this.baseWaterColor],
          blendColor: [..._this.blendColor],
          frequency: _this.frequency,
          animationSpeed: _this.animationSpeed,
          amplitude: _this.amplitude,
          specularIntensity: _this.specularIntensity,
          fadeFactor: _this.fadeFactor,
          velocity: [..._this.velocity]
        };
      }, updatePolygonPrimitive));

      function createPolygonPrimitive() {
        _this._primitive && g3xWaterManager.destroyWaterPolygonPrimitive(_this._primitive);
        _this._primitive = undefined;

        _this._groundPrimitive && g3xWaterManager.destroyWaterPolygonPrimitive(_this._groundPrimitive);
        _this._groundPrimitive = undefined;

        var cartesians = [];

        var l = _this.positions.length / 2;

        if (l < 3) {
          return;
        }

        for (var i = 0; i < l; ++i) {
          var cartesian = Cesium.Cartesian3.fromRadians(_this.positions[i * 2 + 0], _this.positions[i * 2 + 1], _this
            .height);
          cartesians.push(cartesian);
        }
        if (!_this.ground) {
          _this._primitive = g3xWaterManager.createWaterPolygonPrimitive(cartesians, false);
        } else {
          _this._groundPrimitive = g3xWaterManager.createWaterPolygonPrimitive(cartesians, true);
        }
      };

      function updateBoundingSphere() {
        var l = _this.positions.length / 2;
        if (l >= 3) {
          var positionsWithHeight = [];
          for (var i = 0; i < l; ++i) {
            positionsWithHeight.push(_this.positions[i * 2], _this.positions[i * 2 + 1], _this.height);
          }
          var cartesians = Cesium.Cartesian3.fromRadiansArrayHeights(positionsWithHeight);
          _this._boundingSphere = Cesium.BoundingSphere.fromPoints(cartesians, _this._boundingSphere);
        }
      };

      _this.disposers.push(reaction(() => {
        return {
          positions: [..._this.positions],
          height: _this.height,
          ground: _this.ground
        };
      }, () => {
        createPolygonPrimitive();
        updatePolygonPrimitive();
        updateBoundingSphere();
      }, {
        fireImmediately: true
      }));
    }

    _this._polyline = new G3xPolyline(viewer);
    disposers.push(() => {
      return _this._polyline = _this._polyline && _this._polyline.destroy();
    });

    {
      _this._polyline.material.type = 'ColorMaterial';
      _this._polyline.depthTest = false;
      _this._polyline.loop = true;

      disposers.push(autorun(() => {
        _this._polyline.material.ColorMaterial.material.color = _this.outline.color;
        _this._polyline.width = _this.outline.width;
        _this._polyline.show = _this.show && _this.outline.show;
        _this._polyline.ground = _this.ground;
      }));

      {
        function getPolylinePositions() {
          var l = _this.positions.length / 2;
          var positions = [];
          for (var i = 0; i < l; ++i) {
            positions.push([_this.positions[i * 2], _this.positions[i * 2 + 1], _this.height]);
          }
          return positions;
        };

        function setPolylinePositions(positions) {
          return _this._polyline && (_this._polyline.positions = positions);
        };
        setPolylinePositions(getPolylinePositions());
        disposers.push(reaction(getPolylinePositions, setPolylinePositions));
      }
    }

    /**
     * 是否在三维窗口中编辑
     * @name editing
     * @type {boolean}
     * @instance
     * @default false
     * @memberof Obj.Water
     */

    /**
     * 是否在三维窗口中进行点增加的编辑
     * @name creating
     * @type {boolean}
     * @instance
     * @default false
     * @memberof Obj.Water
     */

    disposers.push(g3vUtils.InteractionProperty.registerPolygonCreatingWithHeight(viewer,
      _this, {
        polygonCreatingWithHeight: 'creating'
      }));

    disposers.push(g3vUtils.InteractionProperty.registerPolygonEditing(viewer, _this, {
      polygonEditingProperty: 'editing'
    }));
  }
}

(0, g3xExtends)(G3xWater);
(0, initSchema)(G3xWater);

export default G3xWater;
export {
  G3xWater
};
